package c09泛型;

import java.io.Serializable;
import java.util.*;

public class 通配符和上限 {

	public static void main(String[] args) {
		List<Integer> l = new ArrayList<>();

		List l1 = new ArrayList();
		l1 = l;//正确！因为l1不做类型检查，元素都是Object类型的！
		l1.add(0);//正确！

		List<Object> l2 = new ArrayList<>();
//		l2=l;//编译错误！因为List<Integer>不是List<Object>的子类！
		l2.add(0);//正确！因为l2的元素是Object类型的

		List<Number> l3 = new ArrayList<>();
//		l3=l;//编译错误！因为List<Integer>不是List<Number>的子类！
		l3.add(0);//正确！
//		l3.add(new Object());//编译错误，提示强制转换！

		//使用通配符
		List<?> l4 = new ArrayList<>();
		l4 = l;//正确！因为List<?>代表各种泛型List的父类
		l4 = l1;//正确！
		l1 = l4;//正确！
//		l4.add(0);//编译错误！因为不知道l4的元素类型！
		l4.add(null);//正确！因为null是所有引用类型的实例！
//		Integer I=l4.get(0);//编译错误，提示强制转换！因为返回的是Object类型！

		//设定类型通配符的上限
		List<? extends Number> l5 = new ArrayList<>();//表示所有元素是Number或其子类的泛型List。
		l5 = l;//正确！
		l5 = l1;//正确！
//		l5=l2;//编译错误！类型不兼容
		l5 = l3;//正确！
//		l5=l4;//编译错误，提示强制转换！可以理解为l4的范围更大
		Integer I = new Integer(0);
//		l5.add(0);//编译错误！因为不知道l5的元素类型！
//		l5.add(I);//编译错误！因为不知道l5的元素类型！
		Number N = I;
//		l5.add(N);//编译错误！即使是Number类型也不行！因为不知道l5的元素类型！
//		I=l5.get(0);//编译错误，提示强制转换！因为返回的是Object类型！

		//设定类型通配符形参的上限
//		List<T extends Number> l6=new ArrayList<>();//编译错误！这种形式只能在定义类型形参时使用：
		class MyList<T extends Number> {
		}
//		class MyList2<? extends Number>{}//编译错误！?只能在使用类型泛型时使用！
		MyList<Number> mln = new MyList();//正确！
		MyList<Integer> mli = new MyList();//正确！
//		MyList<Object> mlo=new MyList();//编译错误！Object不是Number类型也不是其子类！

		//多上限
		//类似于类同时继承与实现，接口必须放在父类后面，但是多个接口之间用&连接而不是用逗号！
		class MyLists<T extends Number & Serializable & Comparable> {
		}
		//多上限只能用在定义类型形参时，而不能用在使用类型形参时！
//		List<? extends Number&Serializable&Comparable> l52=new ArrayList<>();//编译错误！
	}

}
